/* Repository for game data relevant to multiple AI behaviors.  Examples include:
		--Current unit counts
		--Resource counts
		--Building counts/types
		--Attacking? Defending?
		--"Spy/scouting" reports of enemy buildings/units
		--Building locations
		--etc

*/

#include "BlackBoard.h"
#include "priorityqueue.h"

BlackBoard::BlackBoard()	:	mineralBalanceToSpend(50),
								gasBalanceToSpend(0),
								mineralsLastFrame(50),
								gasLastFrame(0),
								supplyBalanceToSpend((BWAPI::Broodwar->self()->supplyTotal()-BWAPI::Broodwar->self()->supplyUsed())/2),
								realSupplyUsed(BWAPI::Broodwar->self()->supplyUsed()/2),
								refineryFrameCount(0),
								scanForRefinery(false),
								enemyGroundNumber(0),
								enemyAirNumber(0),
								cloakedEnemyPos(0,0),
								isCloakedEnemy(false),
								randomRoll(0.0)
{
	build = new BuildOrder("1 Rax FE", BWAPI::UnitTypes::Terran_SCV, &oneRaxFE[0], 6);
	threatMap = 0;
}

void BlackBoard::Initialize()
{
	std::set<BWAPI::Unit*> units = BWAPI::Broodwar->self()->getUnits();
	std::list<BWAPI::Unit*>* workers = new std::list<BWAPI::Unit*>;
	BWAPI::Unit* cc;
	BWAPI::UnitType typ;
	for(std::set<BWAPI::Unit*>::iterator it = units.begin(); it != units.end(); it++)
	{
		typ = (*it)->getType();
		if(BWAPI::UnitTypes::Terran_SCV == typ)
		{
			workers->push_back(*it);
		}
		else if(BWAPI::UnitTypes::Terran_Command_Center == typ)
			cc = *it;
		AddUnitGeneral(*it);
	}
	mainBase = new Base(cc->getTilePosition(), cc, workers);
	bases.push_back(mainBase);
	currentOrder = build->GetOrder(realSupplyUsed/2);

	std::set<BWAPI::Unit*> minerals = BWAPI::Broodwar->getStaticMinerals();
	PriorityQueue pq(minerals.size());
	int distance = 0, count = 0, resourceGroup = -1;
	BWAPI::Unit* min;
	for(std::set<BWAPI::Unit*>::iterator it = minerals.begin(); it != minerals.end(); it++)
	{
		distance = (*it)->getPosition().getApproxDistance(cc->getPosition());
		if(distance > 350)
		{
			pq.Add(*it,distance);
			++count;
		}
	}
	for (int i = 0; i < count; i++)
	{
		min = (BWAPI::Unit*)pq.Extract_Min();
		if(min->getResourceGroup() != resourceGroup)
		{
			resourceGroup = min->getResourceGroup();
			possibleExpansions.push_back(min->getTilePosition());
		}
	}

	threatMap = new ThreatMap();
	marineSMs.clear();

	randomRoll = rand() % 100;
}
void BlackBoard::ScanForRefinery()
{
	scanForRefinery = true;
	refineryFrameCount = BWAPI::Broodwar->getFrameCount();
}

void BlackBoard::UpdateGameState()
{
	//mineralBalanceToSpend = (BWAPI::Broodwar->self()->minerals() > mineralsLastFrame) ? mineralBalanceToSpend + BWAPI::Broodwar->self()->minerals() - mineralsLastFrame : mineralBalanceToSpend;
	////Prevent balance from drifting
	//if((BWAPI::Broodwar->self()->minerals() - mineralBalanceToSpend < 25) )
	//	mineralBalanceToSpend = BWAPI::Broodwar->self()->minerals();
	//gasBalanceToSpend = (BWAPI::Broodwar->self()->gas() > gasLastFrame) ? gasBalanceToSpend + BWAPI::Broodwar->self()->gas() - gasLastFrame : gasBalanceToSpend;
	//if((BWAPI::Broodwar->self()->gas() - gasBalanceToSpend  < 15) && (BWAPI::Broodwar->self()->gas() - gasBalanceToSpend  >= 0))
	//	gasBalanceToSpend = BWAPI::Broodwar->self()->gas();
	randomRoll = rand() % 100;
	
	mineralBalanceToSpend = mineralsLastFrame;
	gasBalanceToSpend = gasLastFrame;

	supplyBalanceToSpend = (BWAPI::Broodwar->self()->supplyTotal() - realSupplyUsed)/2;

	mineralsLastFrame = BWAPI::Broodwar->self()->minerals();
	gasLastFrame = BWAPI::Broodwar->self()->gas();

	currentOrder = build->GetOrder(BWAPI::Broodwar->self()->supplyUsed()/2);

	for(std::map<BWAPI::UnitType,BuildingCallback>::iterator it = isBuild.begin(); it != isBuild.end(); it++)
	{
		//hack
		if(it->first != BWAPI::UnitTypes::Terran_Refinery)
		{
			if(!it->second.canScheduleToBuild)
			{
				if(it->second.Expired())
				{
					it->second.canScheduleToBuild = true;
					mineralBalanceToSpend += it->first.mineralPrice();
					gasBalanceToSpend += it->first.gasPrice();
				}
			}
		}
	}

	UpdateBuildingBuildings();

	//threatMap->Refresh();
	/*
	std::list<MarineSM*>::iterator marineBegin = marineSMs.begin(), marineEnd = marineSMs.end();
	while(marineBegin != marineEnd)
	{
		MarineSM* marine = *marineBegin;
		if(marine->expired())
		{
			marineSMs.erase(marineBegin);
			delete marine;
		}
		else
		{
			marine->onFrame();
		}
		marineBegin++;
	}
	*/
}

void BlackBoard::AddEnemyBase(BWAPI::Unit* enemy)
{
	std::list<Base*>::iterator it = enemyBases.begin();
	for(; it != enemyBases.end(); it++)
	{
		if((*it)->GetCC() == enemy)
			break;
	}
	if(it != enemyBases.end())
	{
		//already been added
	}
	else
	{
		enemyBases.push_back(new Base(enemy->getTilePosition(), enemy, NULL, false));
	}
}

void BlackBoard::AddEnemyUnit(BWAPI::Unit* enemy)
{
	bool foundCC = false;
	if(enemy->getType() == BWAPI::UnitTypes::Terran_Command_Center || \
		enemy->getType() == BWAPI::UnitTypes::Protoss_Nexus || \
		enemy->getType() == BWAPI::UnitTypes::Zerg_Hatchery)
	{
		AddEnemyBase(enemy);
		foundCC = true;
	}
	std::map<BWAPI::UnitType,std::set<BWAPI::Unit*>>::iterator it = enemyUnits.find(enemy->getType());
	if(it == enemyUnits.end())
	{
		std::set<BWAPI::Unit*> units;
		units.insert(enemy);
		enemyUnits[enemy->getType()] = units;
		if(enemy->getType().isFlyer())
			++enemyAirNumber;
		else if((!enemy->getType().isWorker())&&(!enemy->getType().isBuilding()))
			++enemyGroundNumber;
	}
	else
	{
		std::pair<std::set<BWAPI::Unit*>::iterator,bool> isNew;
		isNew = it->second.insert(enemy);
		if(isNew.second)
		{
			if(enemy->getType().isFlyer())
				++enemyAirNumber;
			else if((!enemy->getType().isWorker())&&(!enemy->getType().isBuilding()))
				++enemyGroundNumber;

		}
	}
	if(enemyBases.size() > 0)
	{
		if(enemy->getType().isBuilding() || enemy->getType().isWorker())
		{
			Base* baseToBeAddedTo = NULL;
			double distance = INT_MAX;
			double temp;
			for(std::list<Base*>::iterator it = enemyBases.begin(); it != enemyBases.end(); it++)
			{
				if(temp = enemy->getTilePosition().getDistance((*it)->GetBaseLocation()) < distance)
				{
					baseToBeAddedTo = *it;
					distance = temp;
				}
			}
			if(baseToBeAddedTo)
				baseToBeAddedTo->AddUnit(enemy);

		}
	}
 
	if(enemy->getType().isBuilding())
	{
		std::map<BWAPI::UnitType,std::list<BWAPI::TilePosition>>::iterator it = enemyBuildingPositions.find(enemy->getType());
		
		if(it == enemyBuildingPositions.end()) //New type of building
		{
			std::list<BWAPI::TilePosition> buildings;
			buildings.push_back(enemy->getTilePosition());

			enemyBuildingPositions.insert(std::pair<BWAPI::UnitType,std::list<BWAPI::TilePosition>>(enemy->getType(),buildings));
		}
		else //Building type already in buildingLookup
		{
			std::list<BWAPI::TilePosition>::iterator pos = it->second.begin();
			for(; pos != it->second.end(); pos++)
			{
				if((*pos) == enemy->getTilePosition())
					break;
			}
			if(pos == it->second.end())
				it->second.push_back(enemy->getTilePosition());
		}
	}
}

bool BlackBoard::GetCloakedEnemyPosition(BWAPI::Position* toReturn)
{
	if(isCloakedEnemy)
	{
		*toReturn = cloakedEnemyPos;
		isCloakedEnemy = false;
		return true;
	}
	return false;
}


std::set<BWAPI::Unit*>* BlackBoard::GetEnemyUnitsByType(BWAPI::UnitType typ)
{
	std::map<BWAPI::UnitType,std::set<BWAPI::Unit*>>::iterator it = enemyUnits.find(typ);
	if(it != enemyUnits.end())
		return &(it->second);
	return NULL;

}

void BlackBoard::RemoveEnemyUnit(BWAPI::Unit* enemy)
{
	std::map<BWAPI::UnitType,std::set<BWAPI::Unit*>>::iterator it = enemyUnits.find(enemy->getType());
	double distance = double(INT_MAX);
	BWAPI::TilePosition unitPos = enemy->getTilePosition();
	Base* baseThatOwnsUnit = NULL;
	std::list<Base*>::iterator baseToGetRidOf;
	for(std::list<Base*>::iterator ebase = enemyBases.begin(); ebase != enemyBases.end(); ebase++)
	{
		if(unitPos.getDistance((*ebase)->GetBaseLocation()) < distance)
		{
			distance = unitPos.getDistance((*ebase)->GetBaseLocation());
			baseThatOwnsUnit = (*ebase);
			baseToGetRidOf = ebase;
		}
	}
	if(baseThatOwnsUnit)
	{
		baseThatOwnsUnit->RemoveUnit(enemy);
		if(baseThatOwnsUnit->DeleteThisBase())
			enemyBases.erase(baseToGetRidOf);

	}
	
	if(it != enemyUnits.end())
	{
		it->second.erase(enemy);
		if(enemy->getType().isFlyer())
			--enemyAirNumber;
		else if ((!enemy->getType().isWorker())&&(!enemy->getType().isBuilding()))
			--enemyGroundNumber;
	}
	if(enemy->getType().isBuilding())
	{
		std::map<BWAPI::UnitType,std::list<BWAPI::TilePosition>>::iterator it = enemyBuildingPositions.find(enemy->getType());
		
		if(it != enemyBuildingPositions.end())
		{
			std::list<BWAPI::TilePosition>::iterator pos = it->second.begin();
			for(; pos != it->second.end(); pos++)
			{
				if((*pos) == enemy->getTilePosition())
					break;
			}
			if(pos != it->second.end())
				it->second.erase(pos);
		}
	}
}


void BlackBoard::AddUnit(BWAPI::Unit* inc)
{
	double distance = double(INT_MAX);
	BWAPI::TilePosition unitPos = inc->getTilePosition();
	Base* baseThatOwnsUnit = NULL;
	
	if(inc->getType().isBuilding())
	{
		
		std::map<BWAPI::UnitType,BuildingCallback>::iterator it = isBuild.find(inc->getType());
		if(it != isBuild.end())
		{
			it->second.canScheduleToBuild = true;	
		}
		else
		{
			//shoudl never happen
		}
	}

	if (inc->getType() == BWAPI::UnitTypes::Terran_Command_Center)
	{
		std::list<BWAPI::Unit*>* scvs = new std::list<BWAPI::Unit*>;
		scvs->push_back(inc->getBuildUnit());
		for(std::list<Base*>::iterator it = bases.begin(); it != bases.end(); it++)
		{
			if((*it)->RemoveUnit(inc))	break;
		}

		bases.push_back( new Base(inc->getTilePosition(),inc,scvs) );	

	}
	else
	{
		for(std::list<Base*>::iterator it = bases.begin(); it != bases.end(); it++)
		{
			if(unitPos.getDistance((*it)->GetBaseLocation()) < distance)
			{
				distance = unitPos.getDistance((*it)->GetBaseLocation());
				baseThatOwnsUnit = (*it);
			}
		}
		if(baseThatOwnsUnit)
		{
			baseThatOwnsUnit->AddUnit(inc);
		}
	}
	AddUnitGeneral(inc);
}

void BlackBoard::AddUnitGeneral(BWAPI::Unit* unit)
{
	if(unit->getType().isBuilding())
	{
		AddBuildingGeneral(unit);
	}
	else
	{
		std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = unitLookup.find(unit->getType());
		if(it == unitLookup.end()) //New type of unit
		{
			std::list<BWAPI::Unit*> units;
			units.push_back(unit);
			unitLookup.insert(std::pair<BWAPI::UnitType,std::list<BWAPI::Unit*>>(unit->getType(),units));
		}
		else //Unit type already in unitLookup
		{
			it->second.push_back(unit);
		}

		if(unit->getType() == BWAPI::UnitTypes::Terran_Marine)
		{
			marineSMs.push_back(new MarineSM(unit));
		}
	}
}

void BlackBoard::AddBuildingBuildingGeneral(BWAPI::Unit* building)
{
	std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = buildingBuildings.find(building->getType());
	if(it == buildingBuildings.end()) //New type of building
	{
		std::list<BWAPI::Unit*> buildings;
		buildings.push_back(building);
		buildingBuildings.insert(std::pair<BWAPI::UnitType,std::list<BWAPI::Unit*>>(building->getType(),buildings));
	}
	else //Building type already in buildingLookup
	{
		it->second.push_back(building);
	}
}

void BlackBoard::AddBuildingGeneral(BWAPI::Unit* building)
{
	std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = buildingLookup.find(building->getType());
	if(it == buildingLookup.end()) //New type of building
	{
		std::list<BWAPI::Unit*> buildings;
		buildings.push_back(building);
		buildingLookup.insert(std::pair<BWAPI::UnitType,std::list<BWAPI::Unit*>>(building->getType(),buildings));
	}
	else //Building type already in buildingLookup
	{
		it->second.push_back(building);
	}
	AddBuildingBuildingGeneral(building);
}

bool BlackBoard::RemoveUnitGeneral(BWAPI::Unit* unit)
{
	if(unit->getType().isBuilding())
	{
		return RemoveBuildingGeneral(unit);
	}
	else
	{
		std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = unitLookup.find(unit->getType());
		if(it != unitLookup.end()) //New type of unit
		{
			for(std::list<BWAPI::Unit*>::iterator unitInList = it->second.begin(); unitInList != it->second.end(); unitInList++)
			{
				if((*unitInList) == unit)
				{
					it->second.erase(unitInList);
					return true;
				}
			}
		}
	}
	return false;
}

bool BlackBoard::RemoveBuildingGeneral(BWAPI::Unit* unit)
{
	std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = buildingLookup.find(unit->getType());
	if(it != buildingLookup.end()) //New type of unit
	{
		std::map<BWAPI::UnitType,std::list<BWAPI::Unit*>>::iterator it = buildingLookup.find(unit->getType());
		if(it != buildingLookup.end()) //New type of unit
		{
			for(std::list<BWAPI::Unit*>::iterator unitInList = it->second.begin(); unitInList != it->second.end(); unitInList++)
			{
				if((*unitInList) == unit)
				{
					it->second.erase(unitInList);
					return true;
				}
			}
		}
	}
	return false;
}

bool BlackBoard::isBuildMechUnits()
{
	if(bases.size() < 2)	return true;
	else
	{
		BWAPI::Race enemyRace = BWAPI::Broodwar->enemy()->getRace();
		if(enemyRace == BWAPI::Races::Terran)
		{
			if(randomRoll >= 10)
				return true;
			else
				return false;
		}
		else if (enemyRace == BWAPI::Races::Protoss)
		{
			if(randomRoll >= 50)
				return true;
			else
				return false;

		}
		else if(enemyRace == BWAPI::Races::Zerg)
		{
			return true;

		}
		else
		{
			return true;
		}
	}
}

bool BlackBoard::isBuildInfantryUnits()
{
	if(bases.size() < 2)	return true;
	else
	{
		BWAPI::Race enemyRace = BWAPI::Broodwar->enemy()->getRace();
		if(enemyRace == BWAPI::Races::Terran)
		{
			if(randomRoll < 10)
				return true;
			else
				return false;
		}
		else if (enemyRace == BWAPI::Races::Protoss)
		{
			if(randomRoll < 50)
				return true;
			else
				return false;

		}
		else if(enemyRace == BWAPI::Races::Zerg)
		{
			return true;
		}
		else
		{
			return true;
		}
	}
}

bool BlackBoard::isBuildAirUnits()
{
	if(bases.size() < 2)	return true;
	else
	{
		BWAPI::Race enemyRace = BWAPI::Broodwar->enemy()->getRace();
		if(enemyRace == BWAPI::Races::Terran)
		{
			return true;
		}
		else if (enemyRace == BWAPI::Races::Protoss)
		{
			return true;
		}
		else if(enemyRace == BWAPI::Races::Zerg)
		{
			return true;
		}
		else
		{
			return true;	
		}
	}
}

bool BlackBoard::isBuildResearchBuildings()
{
	std::list<BWAPI::Unit*>* bar = GetBuildingsByTypeGeneral(BWAPI::UnitTypes::Terran_Barracks);
	bool checkOne = (bar) ? bar->size() > 0 : false;
	return checkOne && (BWAPI::Broodwar->self()->supplyUsed()/(70*2) < bases.size() && BWAPI::Broodwar->self()->cumulativeMinerals() < ( 4200 * bases.size()));
}

bool BlackBoard::isBuildProductionBuildings()
{
	int supply = BWAPI::Broodwar->self()->supplyUsed()/2;
	return (BWAPI::Broodwar->self()->supplyUsed()/(70*2) < bases.size() && BWAPI::Broodwar->self()->cumulativeMinerals() < ( 4200 * bases.size()));
}

int BlackBoard::NumberOfEnemyAirUnits()
{
	return enemyAirNumber;
}

int BlackBoard::NumberOfEnemyGroundUnits()
{
	return enemyGroundNumber;
}

void BlackBoard::RemoveUnit(BWAPI::Unit* inc)
{
	double distance = double(INT_MAX);
	BWAPI::TilePosition unitPos = inc->getTilePosition();
	Base* baseThatOwnsUnit = NULL;
	for(std::list<Base*>::iterator it = bases.begin(); it != bases.end(); it++)
	{
		if(unitPos.getDistance((*it)->GetBaseLocation()) < distance)
		{
			distance = unitPos.getDistance((*it)->GetBaseLocation());
			baseThatOwnsUnit = (*it);
		}
	}
	if(baseThatOwnsUnit)
	{
		baseThatOwnsUnit->RemoveUnit(inc);
	}
	RemoveUnitGeneral(inc);
}

std::list<BWAPI::Unit*>* BlackBoard::GetUnitsByTypeGeneral(BWAPI::UnitType type)
{
	if(type.isBuilding())
		return GetBuildingsByTypeGeneral(type);
	else
	{
		std::map<BWAPI::UnitType, std::list<BWAPI::Unit*>>::iterator it = unitLookup.find(type);
		if(it != unitLookup.end())	return &(it->second);
		return NULL;
	}
}

std::list<BWAPI::Unit*>* BlackBoard::GetBuildingsByTypeGeneral(BWAPI::UnitType type)
{
	std::map<BWAPI::UnitType, std::list<BWAPI::Unit*>>::iterator it = buildingLookup.find(type);
	if(it != buildingLookup.end())	return &(it->second);
	return NULL;
}

std::list<BWAPI::Unit*>* BlackBoard::GetBuildingBuildingsByTypeGeneral(BWAPI::UnitType type)
{
	std::map<BWAPI::UnitType, std::list<BWAPI::Unit*>>::iterator it = buildingBuildings.find(type);
	if(it != buildingBuildings.end())	return &(it->second);
	return NULL;
}

void BlackBoard::SpendResources(BWAPI::UnitType type)
{
	SpendMinerals(type.mineralPrice());
	SpendGas(type.gasPrice());
	supplyBalanceToSpend += (type.supplyProvided()-type.supplyRequired())/2;
}

void BlackBoard::SpendGas(unsigned int gas)
{
	//assert(gasBalanceToSpend - gas < 5000000);
	gasBalanceToSpend -= gas;
}

void BlackBoard::SpendMinerals(unsigned int min)
{
	//assert(mineralBalanceToSpend - min < 5000000);
	mineralBalanceToSpend -= min;
}

void BlackBoard::Refund(BWAPI::UnitType typ)
{
	mineralBalanceToSpend += typ.mineralPrice();
	gasBalanceToSpend += typ.gasPrice();
	supplyBalanceToSpend += (typ.supplyRequired()-typ.supplyProvided())/2;
}

bool BlackBoard::isResearch(BWAPI::TechType type)
{
	DEBUG_PRINT("Current Order type to build(%p); unit type requesting build(%p); current order(%d); minerals required(%d).\n",currentOrder->typeToBuild, type, currentOrder->order, type.mineralPrice());
	if(!BWAPI::Broodwar->self()->isResearching(type) && !BWAPI::Broodwar->self()->hasResearched(type))
	{
		if(BB->GetMineralsToSpend() >= type.mineralPrice() && BB->GetGasToSpend() >= type.gasPrice() && !BWAPI::Broodwar->self()->hasResearched(type))
		{
			BWAPI::UnitType upgrader = type.whatResearches();
			std::list<BWAPI::Unit*>* units = GetUnitsByTypeGeneral(upgrader);
			if(!units) //We don't have a pre req
				return false;
			std::list<BWAPI::Unit*>::iterator guy = units->begin();
			if( units->front()->getType().isBuilding())
			{
				for(; guy != units->end(); guy++)
				{
					if((*guy)->isCompleted() && !(*guy)->isResearching())
						break;
				}
				if(guy == units->end())
					return false;
			}
			else
				return false;
			return true;
		}
	}
	return false;
}


bool BlackBoard::isResearch(BWAPI::UpgradeType type, int upgradeLevel)
{
	//DEBUG_PRINT("Current Order type to build(%p); unit type requesting build(%p); current order(%d); minerals required(%d).\n",currentOrder->typeToBuild, type, currentOrder->order, type.mineralPrice());
	//int upgradeLevel = BWAPI::Broodwar->self()->getUpgradeLevel(type);
	if(!BWAPI::Broodwar->canUpgrade(NULL,type))
		return false;
	if(!BWAPI::Broodwar->self()->isUpgrading(type) && upgradeLevel > BWAPI::Broodwar->self()->getUpgradeLevel(type) )
	{
		if(BB->GetMineralsToSpend() >= (type.mineralPrice(upgradeLevel))&& BB->GetGasToSpend() >= type.gasPrice(upgradeLevel) && BWAPI::Broodwar->self()->getUpgradeLevel(type) <= type.maxRepeats())
		{	
			BWAPI::UnitType upgrader = type.whatUpgrades();
			std::list<BWAPI::Unit*>* units = GetUnitsByTypeGeneral(upgrader);
			if(!units) //We don't have a pre req
				return false;
			std::list<BWAPI::Unit*>::iterator guy = units->begin();
			if( units->front()->getType().isBuilding())
			{
				for(; guy != units->end(); guy++)
				{
					if((*guy)->isCompleted() && !(*guy)->isUpgrading())
						break;
				}
				if(guy == units->end())
					return false;
			}
			else
				return false;
			return true;
		}
	}
	return false;
}

//CheckConditions
bool BlackBoard::isBuildUnit(BWAPI::UnitType type)
{
	DEBUG_PRINT("Current Order type to build(%p); unit type requesting build(%p); current order(%d); minerals required(%d).\n",currentOrder->typeToBuild, type, currentOrder->order, type.mineralPrice());
	std::list<BWAPI::Unit*>* units;
	if(BB->GetMineralsToSpend() >= type.mineralPrice() && BB->GetGasToSpend() >= type.gasPrice() && (BWAPI::Broodwar->self()->supplyTotal()-BWAPI::Broodwar->self()->supplyUsed())/2 > type.supplyRequired()/2)
	{
		std::map<BWAPI::UnitType, int> preReq = type.requiredUnits();
		for(std::map<BWAPI::UnitType, int>::iterator it = preReq.begin(); it != preReq.end(); it++)
		{
			units = GetUnitsByTypeGeneral(it->first);
			if(!units) //We don't have a pre req
				return false;
			if (units->size() < 1)
				return false;
			std::list<BWAPI::Unit*>::iterator guy = units->begin();
			if( units->front()->getType().isBuilding())
			{
				for(; guy != units->end(); guy++)
				{
					if((*guy)->isCompleted())
						break;
				}
				if(guy == units->end())
					return false;
			}
		}
		//if(currentOrder->typeToBuild == type && (currentOrder->order == BUILD_BUILDIDNG || currentOrder->order == BUILD_UNIT))
		//{
		//if(bases.front()->GetBuildingsByType(type.whatBuilds().first))//  BWAPI::UnitTypes::TER
			return true;
		//}
	}
	return false;

}

void BlackBoard::ResetOrder()
{
	//build->ResetOrder(BWAPI::Broodwar->self()->supplyUsed()/2);

}

void BlackBoard::UpdateBuildingBuildings()
{
	//Only one unit type per call to this
	std::list<BWAPI::Unit*>::iterator toDelete;
	bool isDelete = false;
	for(std::map<BWAPI::UnitType, std::list<BWAPI::Unit*>>::iterator it =  buildingBuildings.begin(); it != buildingBuildings.end(); it++)
	{
		for(std::list<BWAPI::Unit*>::iterator build = (*it).second.begin(); build != (*it).second.end(); build++)
		{
			if((*build)->isCompleted())
			{
				isBuild[(*build)->getType()].canScheduleToBuild = true;
				toDelete = build;
				isDelete = true;
			}
			else if(!(*build)->isBeingConstructed())
			{
				std::list<BWAPI::Unit*>* scvs = GetUnitsByTypeGeneral(BWAPI::UnitTypes::Terran_SCV);
				for(std::list<BWAPI::Unit*>::iterator it = scvs->begin(); it != scvs->end(); it++)
				{
					if((*it)->isIdle() || (*it)->isGatheringMinerals())
					{
						(*it)->rightClick(*build);
						break;
					}
				}
			}
		}
		if(isDelete)
		{
			(*it).second.erase(toDelete);
			isDelete = false;
		}
	}
}

bool BlackBoard::isBuildBuilding(BWAPI::UnitType type)
{
	if(GetMineralsToSpend() >= type.mineralPrice() && GetGasToSpend() >= type.gasPrice())
	{
		//if(currentOrder->typeToBuild == type && (currentOrder->order == BUILD_BUILDIDNG || currentOrder->order == BUILD_UNIT))
		//{
		std::list<BWAPI::Unit*>* units;
		std::map<BWAPI::UnitType, int> preReq = type.requiredUnits();
		for(std::map<BWAPI::UnitType, int>::iterator it = preReq.begin(); it != preReq.end(); it++)
		{
			units = GetUnitsByTypeGeneral(it->first);
			if(!units) //We don't have a pre req
				return false;
			std::list<BWAPI::Unit*>::iterator building = units->begin();
			if(units->size() > 0)
			{
				if( units->front()->getType().isBuilding())
				{
					for(; building != units->end(); building++)
					{
						if((*building)->isCompleted())
							break;
					}
					if(building == units->end())
						return false;
				}
			}
			else
				return false;
		}

		//Limit the number of buildings building simultaneously
		std::list<BWAPI::Unit*>* buildingBuildings = GetBuildingBuildingsByTypeGeneral(type);
		if(buildingBuildings)
		{
			if(buildingBuildings->size() > 2)	return false;
		}
		return true;
		//Check that we haven't scheduled another scv to build this building and that scv hasn't started building yet.
		/*std::map<BWAPI::UnitType,BuildingCallback>::iterator it = isBuild.find(type);
		if(it != isBuild.end())
		{
			bool toReturn = it->second.canScheduleToBuild;
			if(toReturn)
			{
				it->second.canScheduleToBuild = false;
				it->second.Schedule();
			}
			return toReturn;	
		}
		else
		{
			isBuild[type].canScheduleToBuild = false;
			isBuild[type].Schedule();
			return true;
		}*/

		//}
	}
	return false;
}
